grammar T;

options {
    language=Python;
}

program : method ;

method
/* name is visible to any rule called by method directly or indirectly.
 *  There is also a stack of these names, one slot for each nested
 *  invocation of method.  If you have a method nested within another
 *  method then you have name strings on the stack.  Referencing
 *  $method.name access the topmost always.  I have no way at the moment
 *  to access earlier elements on the stack.
 */
scope {
name
}
    :   'method' ID '(' ')' {$method::name=$ID.text;} body
    ; 

body:   '{' stat* '}'
    ;

stat:   ID '=' expr ';'
    |   method // allow nested methods to demo stack nature of dynamic attributes
    ;

expr:   mul ('+' mul)* 
    ;

mul :   atom ('*' atom)*
    ;

/** Demonstrate that 'name' is a dynamically-scoped attribute defined
 *  within rule method.  With lexical-scoping (variables go away at
 *  the end of the '}'), you'd have to pass the current method name
 *  down through all rules as a parameter.  Ick.  This is much much better.
 */
atom:   ID  {print "ref "+$ID.text+" from method "+$method::name}
    |   INT {print "int "+$INT.text+" in method "+$method::name}
    ;

ID  :   ('a'..'z'|'A'..'Z')+ ;

INT :   '0'..'9'+ ;

WS  :   (' '|'\t'|'\n')+ {$channel=HIDDEN}
    ;
